﻿using System;
using System.IO.IsolatedStorage;
using System.Linq.Expressions;
using System.Reflection;

namespace Mandarine.MVVM.Command
{
    public class AppSettingsCommand<T> : RelayCommand<T>
	{
        protected IsolatedStorageSettings _isolatedStore;
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="execute"></param>
        /// <param name="canExecute"></param>
        public AppSettingsCommand(Action<T> execute, Predicate<T> canExecute) 
            : base(execute, canExecute)
        {
            if (!System.ComponentModel.DesignerProperties.IsInDesignTool)
            {
                _isolatedStore = IsolatedStorageSettings.ApplicationSettings;
            }
        }
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="execute"></param>
        public AppSettingsCommand(Action<T> execute) 
            : base(execute)
        {
            if (!System.ComponentModel.DesignerProperties.IsInDesignTool)
            {
                _isolatedStore = IsolatedStorageSettings.ApplicationSettings;
            }
        }
        public bool AddOrUpdateValue(Expression<Func<T>> propertyExpression, Object value)
        {
            var propertyName = ExtractPropertyName(propertyExpression);
            return AddOrUpdateValue(propertyName, value);
        }
        /// <summary>
        /// 値を追加又は更新します
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool AddOrUpdateValue(string key, Object value)
        {
            bool valueChanged = false;

            if (_isolatedStore.Contains(key))
            {
                if (_isolatedStore[key] != value)
                {
                    _isolatedStore[key] = value;
                    valueChanged = true;
                }
            }
            else
            {
                _isolatedStore.Add(key, value);
                valueChanged = true;
            }
            return valueChanged;
        }
        /// <summary>
        /// 値を取得します
        /// </summary>
        /// <param name="propertyExpression"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public T GetValueOrDefault(Expression<Func<T>> propertyExpression, T defaultValue)
        {
            var propertyName = ExtractPropertyName(propertyExpression);
            return GetValueOrDefault(propertyName, defaultValue);
        }
        /// <summary>
        /// 値を取得します
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public V GetValueOrDefault<V>(string key, V defaultValue)
        {
            V value;
            if (_isolatedStore.Contains(key))
            {
                value = (V)_isolatedStore[key];
            }
            else
            {
                value = defaultValue;
            }
            return value;
        }
        /// <summary>
        /// データを保存します
        /// </summary>
        public void Save()
        {
            _isolatedStore.Save();
        }
        /// <summary>
        /// 式からプロパティ名を抽出します
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="propertyExpression"></param>
        /// <returns></returns>
        public static string ExtractPropertyName<V>(Expression<Func<V>> propertyExpression)
        {
            if (propertyExpression == null)
            {
                throw new ArgumentNullException("propertyExpression");
            }

            var memberExpression = propertyExpression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new ArgumentException("propertyExpression");
            }

            var property = memberExpression.Member as PropertyInfo;
            if (property == null)
            {
                throw new ArgumentException("propertyExpression");
            }

            var getMethod = property.GetGetMethod(true);
            if (getMethod.IsStatic)
            {
                throw new ArgumentException("propertyExpression");
            }

            return memberExpression.Member.Name;
        }

	}
}
